#include "img.h"

image open_image(string fullpath) {
    //parse fullpath to extract filename and extension
    int* results;
    int match_count = pcre_match("^(/?(?:.*?/)*)(.*)\\.(.{1,4})$", fullpath, &results);
    if(match_count == -1) {
        return NULL;
    }
    string path = strndup(fullpath + results[2], results[3]-results[2]);
    string filename = strndup(fullpath + results[4], results[5]-results[4]);
    string extension = strndup(fullpath + results[6], results[7]-results[6]);
    //create new image
    image img = new_image(path, filename, extension);
    //get file-specific data
    if(!get_file_data(img, "rb")) {
        return NULL;
    }
    //get image data pointer
    img->bitmap = bmp_create_from_file(img->fp);
    img->jpeg = jpeg_create_from_file(img->fp);
    set_dimensions(img);
    return img;
}

image bmp_trim(image img, int block_size) {
    image trimmed = clone(img, TRIM_SUFFIX);
    int W = trimmed->width;
    int H = trimmed->height;
    int w = W - (W % block_size);
    int h = H - (H % block_size);
    int i;
    for(i=0; i<w; i++) {
        trimmed->bitmap->pixels[i] = (rgb_pixel_t*)realloc(trimmed->bitmap->pixels[i], h*sizeof(rgb_pixel_t));
    }
    for(; i<W; i++) {
        free(trimmed->bitmap->pixels[i]);
    }
    trimmed->bitmap->dib.width = w;
    trimmed->bitmap->dib.height = h;
    set_dimensions(trimmed);
    return trimmed;
}
 
image clone(image img, string suffix) {
    image clone = malloc(img->filesize);
    memcpy(clone, img, img->filesize);
    strcat(clone->filename, suffix);
    return clone;
 }

image new_image(string path, string filename, string extension) {
    image img = malloc(sizeof(struct _image));
    img->path = path;
    img->filename = filename;
    img->extension = extension;
    return img;
}
 
int save_image(image img) {
    //decide which method to call according to image type
    if(is_bitmap(img)) {
        bmp_save(img->bitmap, get_fullpath(img));
    } else {
        jpeg_save(img->jpeg, get_fullpath(img));
    }
    //update img's file-specific properties
    if(!(img->fp = get_file_pointer(img, "rb"))) {
        printf("Error reading image file.\n");
        return 0;
    }
    img->md5sum = md5sum(img->fp);
    img->filesize = filesize(img->fp);
    return 1;
}

void close_image(image img) {
    fclose(img->fp);
}

int get_file_data(image img, string mode) {
    if(!(img->fp = get_file_pointer(img, mode))) {
        return 0;
    }
    img->md5sum = md5sum(img->fp);
    img->filesize = filesize(img->fp);
    return 1;
}

FILE* get_file_pointer(image img, string mode) {
    return fopen(get_fullpath(img), mode);
}

void set_dimensions(image img) {
    if(is_bitmap(img)) {
        img->width = bmp_get_width(img->bitmap);
        img->height = bmp_get_height(img->bitmap);
    } else if(is_jpeg(img)) {
        img->width = jpeg_get_width(img->jpeg);
        img->height = jpeg_get_height(img->jpeg);
    } else {
        img->width = img->height = 0;
    }
}

string get_fullpath(image img) {
    return strcat(strcat(strcat(strdup(img->path), img->filename), "."), img->extension);
}

int is_bitmap(image img) {
    return has_extension(img, (string[]){"bmp", "dib", NULL});
}

int is_jpeg(image img) {
    return has_extension(img, (string[]){"jpg", "jpeg", NULL});
}

int has_extension(image img, string* extension) {
    int c = 1;
    string ext;
    while((ext = *extension++) != NULL) {
        c*=strcmp(img->extension, ext);
    }
    return !c;
}

float rgb2mono(rgb_pixel_t pixel) {
	return (0.2125 * pixel.red) + (0.7154 * pixel.green) + (0.0721 * pixel.blue);
}

void details(image img) {
    printf("Image details:\n--------------\nFilename: %s\nExtension: %s\nPath: %s\nWidth: %dpx\nHeight: %dpx\nMD5 checksum: %s\nFile size: %d bytes\nValue: %d\nBitmap value: %d\n--------------\n", img->filename, img->extension, img->path, img->width, img->height, img->md5sum, img->filesize, img, img->bitmap);
}
